package org.magnerfuller.imtoolkit.util;

import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.magnerfuller.imtoolkit.util.exception.OptionParserException;

public abstract class OptionsParser {

  public abstract boolean isValidKey(String key);
  
  public abstract boolean isValidValue(String key, String value);
  
  public abstract boolean hasValue(String key);
  
  public Map<String, String> parse(String text) throws OptionParserException {
    Map<String, String> props = new HashMap<String, String>();
    
    StringTokenizer tokenizer = new StringTokenizer(text);
    
    while(tokenizer.hasMoreTokens()) {
      String token = tokenizer.nextToken();
      String key;
      String value;
      
      // Handle GNU-style options.
      if(token.startsWith("--") && token.length() > 2) {
        key = token.substring(2);
      }
      // Handle POSIX-style options.
      else if(token.startsWith("-") && token.length() > 1) {
        key = token.substring(1);
      }
      // Handle assignment-style options.
      else if(token.contains("=") && !token.startsWith("=") && token.length() > 3) {
        key = (token.split("="))[0];
      }
      // Handle options that are on their own.
      else {
        key = token;
      }
      
      if(isValidKey(key)) {
        if(hasValue(key)) {
          if(token.startsWith("--") || token.startsWith("-")) {
            if(tokenizer.hasMoreTokens()) {
              token = tokenizer.nextToken();
              value = token;
            }
            else {
              throw new OptionParserException("Missing value for key " + key,
                  OptionParserException.MISSING_VALUE, key, null);
            }
          }
          else if(token.contains("=") && !token.startsWith("=") && token.length() > 3) {
            value = (token.split("="))[1];
          }
          else {
            if(tokenizer.hasMoreTokens()) {
              token = tokenizer.nextToken();
              value = token;
            }
            else {
              throw new OptionParserException("Missing value for key " + key,
                  OptionParserException.MISSING_VALUE, key, null);
            }
          }
        }
        else {
          value = null;
        }
      }
      else {
        throw new OptionParserException("Illegal key " + key,
            OptionParserException.INVALID_KEY, key, null);
      }
      
      if(isValidValue(key, value)) {
        props.put(key, value);
      }
      else {
        throw new OptionParserException("Illegal value " + value + " for key " + key,
            OptionParserException.INVALID_KEY, key, value);
      }
    }
    
    return props;
  }
  
  public Map<String, String> parse(String[] text) throws OptionParserException {
    String textStr = "";
    
    for(int i = 0; i < text.length; i++) {
      textStr += text[i] + " ";
    }
    
    return parse(textStr);
  }
}
